#pragma region Copyright
/// <copyright>
/// Copyright (c) 2007 Ilia Shramko.
/// Released under the terms of the GNU Lesser General Public License.
/// </copyright>
#pragma endregion

#pragma once

class HttpRequest;

class HttpResponse
{
private:
	int _refs;
	HttpRequest* _httpRequest;
	DWORD _statusCode;
	CString _statusDescription;
	CString _statusLine;
	HttpHeaderCollection _headers;
	ULONG _contentSize;
	ULONG _contentPosition;
	CComSafeArray<BYTE> _content;

public:
	HttpResponse(HttpRequest* httpRequest) :
	  _refs(1), _statusCode(0), _contentSize(0), _contentPosition(0)
	{
		httpRequest->AddRef();
		_httpRequest = httpRequest;

		ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose, "[%p] HttpResponse::HttpResponse\r\n", this);
	}

	~HttpResponse()
	{
		ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose, "[%p] HttpResponse::~HttpResponse\r\n", this);
		_httpRequest->Release();
	}

	int AddRef()
	{
		return ++_refs;
	}

	int Release()
	{
		if(--_refs == 0)
			delete this;
		return _refs;
	}

	const HttpRequest* GetRequest()
	{
		return _httpRequest;
	}

	DWORD GetStatusCode()
	{
		return _statusCode;
	}

	const CString& GetStatusDescription()
	{
		return _statusDescription;
	}

	const CString& GetStatusLine()
	{
		return _statusLine;
	}

	void SetStatusLine(DWORD statusCode, const wchar_t* statusDescription)
	{
		_statusCode = statusCode;
		if(statusDescription != NULL)
			_statusDescription.Append(statusDescription);
		else
			_statusDescription.Empty();

		_statusLine.Empty();
		_statusLine.AppendFormat(L"HTTP/1.1 %d %s", statusCode, _statusDescription);
	}

	HRESULT AttachContent(SAFEARRAY* content)
	{
		_contentSize = 0;
		_contentPosition = 0;
		_content.Attach(content);
		if(_content != NULL)
			_contentSize = _content.GetCount();
		return S_OK;
	}

	HttpHeaderCollection& GetHeaders()
	{
		return _headers;
	}

	ULONG Read(BYTE* buffer, ULONG size)
	{
		if(buffer == NULL || size == 0)
			return 0;

		if(_content == NULL || _contentSize == 0 || _contentSize <= _contentPosition)
			return 0;

		ULONG copied = min(_contentSize - _contentPosition, size);
		
		for(ULONG i = 0; i < copied; i++)
			buffer[i] = _content.GetAt(_contentPosition + i);

		_contentPosition += copied;
		return copied;
	}

	ULONG GetContentSize()
	{
		return _contentSize;
	}
};
